/*
 * BrowseHistoryEntity.java
 *
 * Created on April 23, 2007, 3:39 PM
 *
 *  Life Logger v1.0
    Copyright (C) 2007  Anand Kishore (anand@semanticvoid.com)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.semanticvoid.lifelogger.entity;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * This class is a subclass of the WebHistory entity. It represents the objects that
 * have been logged by the browser (Google Web History) while surfing the web.
 * @author anand kishore
 */
public class BrowseHistoryEntity extends WebHistoryEntity {
    
    /** The TITLE */
    private String title;
    
    /** The TYPE */
    private short type;
    
    /** The SEARCH CONTEXT */
    private String searchContext;
    
    /** The TEXT CONTEXT */
    private String content;
    
    /** The Search Excerpt */
    private String excerpt;
    
    /** Term Vector */
    private Map<String, Integer> termVector;
    
    /**
     * Empty constructor (REFRAIN FROM USING IT)
     */
    public BrowseHistoryEntity() {
        // EMPTY CONSTRUCTOR
        super(null, null, null);
    }
    
    /**
     * Creates a new instance of BrowseHistoryEntity
     * @param guid the guid
     * @param link the link
     * @param pubDate the date
     * @param title the title
     * @param type the object type
     * @param searchContext the context of search
     * @param content the content
     */
    public BrowseHistoryEntity(String guid, String link, Calendar pubDate, String title, short type, String searchContext, String content) {
        super(guid, link, pubDate);
        this.title = title;
        this.type = type;
        this.searchContext = searchContext;
        this.content = content;
    }
    
    /**
     * Creates a new instance of BrowseHistoryEntity
     * @param guid the guid
     */
    public BrowseHistoryEntity(String guid) {
        super(guid, null, null);
        this.title = null;
        this.type = -1;
        this.searchContext = null;
        this.content = null;
    }
    
    /**
     * Creates a new instance of BrowseHistoryEntity
     * @param guid the guid
     * @param link the link
     * @param pubDate the date
     * @param title the title
     * @param type the object type
     * @param searchContext the context of search
     * @param content the content
     * @param excerpt the excerpt
     */
    public BrowseHistoryEntity(String guid, String link, Calendar pubDate, String title, short type, String searchContext, String content, String excerpt) {
        super(guid, link, pubDate);
        this.title = title;
        this.type = type;
        this.searchContext = searchContext;
        this.content = content;
        this.excerpt = excerpt;
    }
    
    /**
     * Get the title
     * @return the title
     */
    public String getTitle() {
        return title;
    }
    
    /**
     * Set the title
     * @param title the title string
     */
    public void setTitle(String title) {
        this.title = title;
    }
    
    /**
     * Get the entity type
     * @return the type
     */
    public short getType() {
        return type;
    }
    
    /**
     * Set the type
     * @param type the type
     */
    public void setType(short type) {
        this.type = type;
    }
    
    /**
     * Get the search context
     * @return the search context
     */
    public String getSearchContext() {
        return searchContext;
    }
    
    /**
     * Set the search context
     * @param searchContext the search context
     */
    public void setSearchContext(String searchContext) {
        this.searchContext = searchContext;
    }
    
    /**
     * Get the content
     * @return the content string
     */
    public String getContent() {
        return content;
    }
    
    /**
     * Set the content
     * @param content the content string
     */
    public void setContent(String content) {
        this.content = content;
    }
    
    /**
     * The string representation of the object
     * @return the string value of the object
     */
    public String toString() {
        return this.getGuid() + "#" + this.getType() + "#" + this.getPubDate().toString() + "#" + this.getSearchContext() + "#" + this.getTitle() + "#" + this.getLink();
    }
    
    public String getExcerpt() {
        return excerpt;
    }
    
    public void setExcerpt(String excerpt) {
        this.excerpt = excerpt;
    }
    
    public Map<String, Integer> extractTermVectorAsMap() {
        Map<String, Integer> termVectorAsMap = new HashMap<String, Integer>();
        
        
        if(title == null || content == null) {
            return termVectorAsMap;
        }
        
        //@TODO Omit stop words for tokenization
        String[] tokens = (title.toLowerCase() + " " + content.toLowerCase()).split("[ ~!@#$%^&*()_\\-=\\+{}\\[\\]|\\.:;?,<>\"']");
        Collection<String> tokenList_1 = Collections.synchronizedCollection(new ArrayList<String>());
        Collection<String> tokenList_2 = Collections.synchronizedCollection(new ArrayList<String>());
        
        if(tokens != null) {
            tokenList_1.addAll(Arrays.asList(tokens));
            tokenList_2.addAll(Arrays.asList(tokens));
        }
        
        for(String token : tokenList_1) {
            int freq = 1;
            
            if(termVectorAsMap.containsKey(token)) {
                continue;
            }
            
            while(tokenList_2.remove(token)) {
                freq++;
            }
            
            termVectorAsMap.put(token, freq);
        }
        
        return termVectorAsMap;
    }
    
    public String extractTermVectorAsString() {
        Map<String, Integer> termvectorAsMap = extractTermVectorAsMap();
        StringBuffer termVectorAsString = new StringBuffer();
        
        Set<String> keys = termvectorAsMap.keySet();
        
        for(String key : keys) {
            int freq = termvectorAsMap.get(key);
            
            termVectorAsString.append(key + ":" + freq + ", ");
        }
        
        return termVectorAsString.toString();
    }
    
    public double cosineSimilarity(BrowseHistoryEntity b2) {
        int dotProduct = 0;
        int sumOfSqaures_a = 0;
        int sumOfSqaures_b = 0;
        double denominator = 0;
        double ratio = 0;
        
        if(b2 == null) {
            return 0.0d;
        }
        
        Map<String, Integer> vector_a = this.getTermVector();
        Map<String, Integer> vector_b = b2.getTermVector();
        
        Iterator itr_a = vector_a.keySet().iterator();
        
        while(itr_a.hasNext()) {
            String word = (String) itr_a.next();
            
            long a_freq = vector_a.get(word);
            long b_freq = 0;
            
            if(vector_b.containsKey(word)) {
                b_freq = vector_b.get(word);
            }
            
            dotProduct += (a_freq * b_freq);
            sumOfSqaures_a += a_freq * a_freq;
            sumOfSqaures_b += b_freq * b_freq;
        }
        
        //System.out.println("dotProduct: " + dotProduct + "SOS_a: " + sumOfSqaures_a + "SOS_b: " + sumOfSqaures_b);
        
        denominator = Math.sqrt(sumOfSqaures_a) * Math.sqrt(sumOfSqaures_b);
        
        //System.out.println("denominator: " + denominator);
        
        ratio = dotProduct / denominator;
        
        //System.out.println("ratio: " + ratio);
        
        return Math.acos(ratio);
    }
    
    public boolean equals(Object o) {
        BrowseHistoryEntity b2 = (BrowseHistoryEntity) o;
        
        return this.getGuid().equalsIgnoreCase(b2.getGuid());
    }
    
    public int hashCode() {
        return this.getGuid().hashCode();
    }

    public Map<String, Integer> getTermVector() {
        return termVector;
    }

    public void setTermVector(String termVector) {
//        System.out.println(this.getGuid());
        this.termVector = new HashMap<String, Integer>();
        
        String[] pairs = termVector.split(",");
        
        for(String pair : pairs) {
            if(!pair.equals("")) {
                String[] values = pair.split(":");
                
                if(values.length != 2) {
                    continue;
                }

                String word = values[0];
                String freqStr = values[1];
                
                if(word.equals("") || word.equals(" ") || freqStr.equals("") || freqStr.equals("")) {
                    continue;
                }
                
                int freq = Integer.valueOf(freqStr);

                this.termVector.put(word, freq);
            }
        }
    }
}
